#include <iostream>
#include <vector>
#include <pthread.h>
#include <ctime>
#include <unistd.h>
#include "sem.hpp"
#include "lockGuard.hpp"

using namespace std;
#define default_num 5

template <class T>
class RingQueue // 环形队列
{
public:
    RingQueue(int num = default_num)
        : ring_queue(num), _num(num), p_step(0), c_step(0), _space_sem(num), _data_sem(0) {}
    ~RingQueue() {}
    void Push(const T &obj)
    {
        _space_sem.P(); // 先申请空间资源
        {
            lockGuard lock(&pmtx); // 再抢锁
            ring_queue[p_step++] = obj;
            p_step %= _num;
        }
        _data_sem.V(); // 释放数据资源
    }
    void Pop(T &obj)
    {
        _data_sem.P(); // 先申请数据资源
        {
            lockGuard lock(&cmtx); // 再抢锁
            obj = ring_queue[c_step++];
            c_step %= _num;
        }
        _space_sem.V(); // 释放空间资源
    }

private:
    vector<T> ring_queue;
    int _num;           // 容量
    int p_step, c_step; // 生产下标和消费下标

    Sem _space_sem; // 生产者申请空间资源的信号量
    Sem _data_sem;  // 消费者申请数据资源的信号量

    pthread_mutex_t pmtx;
    pthread_mutex_t cmtx; // 两把锁分别保证多生产和多消费之间的竞争互斥关系
};